package com.culture.config.service.impl;

import java.util.Comparator;
import java.util.List;

import javax.annotation.Resource;

import com.culture.config.common.util.BeanUtil;
import com.culture.config.common.util.ExceptionUtil;
import com.culture.config.common.util.FunctionUtil;
import com.culture.config.common.util.JSONUtil;
import com.culture.config.component.AppWorker;
import com.culture.config.component.PropertyWorker;
import com.culture.config.constant.PropertyValueType;
import com.culture.config.dao.entity.App;
import com.culture.config.dao.entity.Property;
import com.culture.config.dao.mapper.AppMapper;
import com.culture.config.dao.mapper.PropertyCopyMapper;
import com.culture.config.dao.mapper.PropertyMapper;
import com.culture.config.service.PropertyService;
import com.culture.config.util.Base64Util;
import com.culture.config.util.PropertiesUtil;
import com.culture.config.service.EventLogService;
import com.culture.config.model.po.*;
import com.culture.config.model.vo.*;
import com.culture.config.wrapper.ApplicationWrapper;
import com.culture.config.wrapper.PropertyWrapper;

import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class PropertyServiceImpl implements PropertyService{
    @Resource
	private PropertyMapper propertyMapper;
	@Resource
	private PropertyCopyMapper propertyCopyMapper;
	@Resource
	private AppMapper appMapper;
    @Autowired
	private EventLogService eventLogService;
	@Autowired
	private AppWorker appWorker;
	@Autowired
	private PropertyWorker propertyWorker;

    @Override
	public Page<ApplicaionVO> pageApplicaions(ApplicationPageParam param) {
		PageMethod.startPage(param.getPageNum(), param.getPageSize());
		Page<App> appList = this.appMapper.page(param.getName());
		return BeanUtil.copyPageProperties(appList, ApplicaionVO.class);
	}	

	@Override
	public List<ApplicaionVO> listApplicaions(ApplicationListParam param) {
		List<App> appList = this.appMapper.list(param.getName());
		return BeanUtil.copyListProperties(appList, ApplicaionVO.class);
	}	
	
	@Override
	public ApplicaionVO addApplicaion(ApplicationAddPO applicationAddPO) {
		App newApp = ApplicationWrapper.wrapAppAdd(applicationAddPO);
		this.appMapper.add(newApp);
		return new ApplicaionVO(newApp.getId());
	}

	@Override
	@Transactional
	public ApplicaionVO updateApplicaion(ApplicationUpdatePO applicationUpdatePO) {
		App app = this.appMapper.get(applicationUpdatePO.getId());
		ExceptionUtil.businessExceptionWhenNull(app, "Update application not exist.");	
		App updateApp = ApplicationWrapper.wrapAppUpdate(applicationUpdatePO, app);
		int ret = this.appMapper.update(updateApp);
		log.info("updateApplicaion id:{},name:{},ret:{}",app.getId(),applicationUpdatePO.getName(),ret);
		if(ret > 0){
			ret = this.propertyMapper.updateByApp(updateApp);
			log.info("updateByApp id:{},name:{},ret:{}",app.getId(),applicationUpdatePO.getName(),ret);
		}
		return new ApplicaionVO(applicationUpdatePO.getId());
	}

	@Override
	public Page<PropertyVO> pageByApp(PropertyPageParam param) {
		PageMethod.startPage(param.getPageNum(), param.getPageSize());
		Page<Property> propertyList = this.propertyMapper.pageByApp(PropertyWrapper.wrapPropertyQuery(param));
		return BeanUtil.copyPageProperties(propertyList, PropertyVO.class,(property,propertyVO)->{
			if(PropertyValueType.PASSWORD.id() == property.getValueType()){
				propertyVO.setPropertyValue("***********");
			}
		});
	}

	@Override
	public List<PropertyVO> getByApp(PropertiesParam param) {
		this.appWorker.get(param.getAppId());
		List<Property> properties = this.propertyMapper.listByApp(PropertyWrapper.wrapPropertyQuery(param));	
		return BeanUtil.copyListProperties(properties, PropertyVO.class);
	}

	@Override
	public String getYamlByApp(PropertiesParam param) {
		this.appWorker.get(param.getAppId());
		List<Property> properties = this.propertyMapper.listByApp(PropertyWrapper.wrapPropertyQuery(param));	
		String yamlStr = PropertiesUtil.propertiesToYaml(FunctionUtil.sort(properties, Comparator.comparing(Property::getPropertyKey)));		
		return Base64Util.encodeToString(yamlStr);
	}
	
	@Override
	public void updateProperties(PropertiesUpdateParam param) {
		App app = this.appWorker.get(param.getAppId());
		this.propertyWorker.updateProperties(app,param);	
	}

	@Override
	@Transactional
	public void update(PropertyUpdateParam param) {
		 Property updateProperty = PropertyWrapper.wrapPropertyUpdate(param);
		 int ret = this.propertyMapper.update(updateProperty);
		 if(ret > 0) {
			 this.eventLogService.addEventLog("updateProperty", JSONUtil.beanToJSONString(updateProperty));
		 }
	}

	@Override
	@Transactional
	public void add(PropertyAddParam param) {
		 Property newProperty = PropertyWrapper.wrapPropertyAdd(param);
		 int ret = this.propertyMapper.add(newProperty);
		 if(ret > 0) {
			 this.eventLogService.addEventLog("addProperty", JSONUtil.beanToJSONString(newProperty));
		 }
	}

	@Override
	@Transactional
	public ApplicaionVO copyApp(ApplicationCopyPO copyPO) {
		App newApp = this.appWorker.copyApp(copyPO);
		this.eventLogService.addEventLog("copyApp", JSONUtil.beanToJSONString(copyPO));
		return new ApplicaionVO(newApp.getId());
	}

	@Override
	@Transactional
	public void syncProperty(PropertySyncPO syncPO) {
		this.propertyWorker.syncProperty(syncPO);
		this.eventLogService.addEventLog("syncProperty", JSONUtil.beanToJSONString(syncPO));
	}	
}
